package model

import (
	"fmt"
	"time"

	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type User struct {
	ID        uint      `gorm:"primaryKey;autoIncrement" json:"id"`
	CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
	UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
	UserName  string    `gorm:"size:64;not null;unique;column:username" json:"username" comment:"账号名"`
	NickName  string    `gorm:"size:64;not null;column:nickname" json:"nickname" comment:"用户名"`
	Password  string    `gorm:"size:128;not null" json:"password" comment:"密码"`
	Email     string    `gorm:"size:64" json:"email" comment:"邮箱"`
	IsSuper   int       `gorm:"default:0" json:"is_super" comment:"是否为超级管理员"`
}

func (u *User) Create(tx *gorm.DB) (uint, error) {
	hashPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
	if err != nil {
		return 0, err
	}

	u.Password = string(hashPassword)
	result := tx.Create(u)
	if result.Error != nil {
		return 0, errors.New("创建用户失败")
	}
	return u.ID, nil
}

func (u *User) UpdatePassword(tx *gorm.DB, password string) (int64, error) {
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return 0, err
	}

	result := tx.Model(u).Where("id = ?", u.ID).Update("password", string(hashedPassword))
	if result.Error != nil {
		return 0, errors.New("更新密码失败")
	}
	return result.RowsAffected, nil
}

func (u *User) CheckPassword(password string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
	return err == nil
}

func (u *User) GetByUserName(tx *gorm.DB, username string) (*User, error) {
	result := tx.Where("username = ? or email = ?", username, username).First(u)
	if result.RowsAffected == 0 {
		return nil, errors.New("用户不存在")
	}
	return u, nil
}

func (u *User) GetByID(tx *gorm.DB, id interface{}) (*User, error) {
	result := tx.Where("id = ?", id).First(u)
	if result.Error != nil {
		return nil, errors.New("用户不存在")
	}
	return u, nil
}

func (u *User) GetLoginUser(ctx *gin.Context, tx *gorm.DB) (user *User, err error) {
	session := sessions.Default(ctx)
	username := session.Get("username")
	if username == nil {
		return nil, errors.New("请先登录")
	}
	user, err = u.GetByUserName(tx, username.(string))
	if err != nil {
		return nil, errors.Errorf("获取用户失败：%s", err.Error())
	}
	return user, nil
}

func (u *User) List(tx *gorm.DB) ([]User, error) {
	var users []User
	result := tx.Find(&users)
	if result.Error != nil {
		return nil, result.Error
	}
	return users, nil
}

func (u *User) Delete(tx *gorm.DB, id interface{}) error {
	if err := tx.Delete(&User{}, id).Error; err != nil {
		return fmt.Errorf("删除用户失败: %w", err)
	}
	return nil
}

func (u *User) Update(tx *gorm.DB) error {
	result := tx.Model(u).Updates(u)
	if result.Error != nil {
		return result.Error
	}
	return nil
}
